#pragma once

#include "Common.hpp"
#include <unistd.h>

namespace SocketModule
{
    const int Gbacklog=8;
    const int defaultfd=-1;

    class Socket
    {
    public:
        ~Socket(){}
        virtual void CreateSocket()=0;
        virtual void BindSocket(uint16_t port)=0;
        virtual void ListenSocket(int backlog)=0;
        virtual std::shared_ptr<Socket> AcceptSocket(InetAddr* client)=0;
        virtual void Close()=0;
        virtual int Recv(std::string* message)=0;
        virtual int Send(std::string& message)=0;
        virtual int Connect(std::string serveip,uint16_t serveport)=0;
    public:
        void BuildTCPSocketfd(uint16_t port,int backlog=Gbacklog)
        {
            CreateSocket();
            BindSocket(port);
            ListenSocket(backlog);
        }
        void BuildTCPClientSockfd()
        {
            CreateSocket();
        }
    };


    class TCPSocket :public Socket
    {
    public:
        TCPSocket():_sockfd(defaultfd){}
        TCPSocket(int sockfd):_sockfd(sockfd)
        {}
        void CreateSocket() override
        {
            _sockfd = ::socket(AF_INET,SOCK_STREAM,0);
            if(_sockfd<0)
            {
                LOG(FATAL)<<"create socket error";
                exit(SOCKET_ERR);
            }
            LOG(INFO)<<"create socket success";
        }
        void BindSocket(uint16_t port) override
        {
            InetAddr local(port);
            int n = ::bind(_sockfd,local.CompulsoryNetAddr(),local.AddrLen());
            if(n<0)
            {
                LOG(FATAL)<<"bind error";
                exit(BIND_ERR);
            }
            LOG(INFO)<<"bind success";

        }
        void ListenSocket(int backlog=Gbacklog) override
        {
            int n=::listen(_sockfd,backlog);
            if(n<0)
            {
                LOG(FATAL)<<"listen error";
                exit(LISTEN_ERR);
            }
            LOG(INFO)<<"listen success";

        }
        std::shared_ptr<Socket> AcceptSocket(InetAddr* client) override
        {
            struct sockaddr_in peer;
            socklen_t len=sizeof(peer);
            int fd=::accept(_sockfd,(sockaddr*)&peer,&len);
            if(fd<0)
            {
                LOG(WARNING)<<"accept unsuccess";
                return nullptr;
            }
            // LOG(INFO)<<"accpet success";
            client->SetAddr(peer);
            return std::make_shared<TCPSocket>(fd);
        }

        void Close() override
        {
            if(_sockfd>=0)
                ::close(_sockfd);
        }
        //参数设置为引用和指针都可以，
        //网络编程中，如果涉及到缓冲区的操作，参数应该尽可能使用指针或者引用
        int Recv(std::string* message) override
        {
            char buffer[4096*3];//一会改大一点试试，应该不是这里的问题，还是不能连接
            //两种读取方式是等价的
            size_t n=::read(_sockfd,buffer,sizeof buffer - 1);
            // size_t n=::recv(_sockfd,buffer,sizeof buffer - 1,0);
            if(n>0)
            {
                buffer[n]=0;
                //处理读取的报文不完整，拼接在原来的后面，可以接着读，直到完整的报文
                *message+=buffer;
            }
            return n;
        }

        int Send(std::string& message) override
        {
            return send(_sockfd,message.c_str(),message.size(),0);
        }
        int Connect(std::string serveip,uint16_t serveport) override
        {
            InetAddr serve(serveip,serveport);
            return ::connect(_sockfd,serve.CompulsoryNetAddr(),serve.AddrLen());
        }
    private:
        int _sockfd;
    };
}